home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / redakcyjne / programy / VideoLAN Client (VLC) 1.0.5 / vlc-1.0.5-win32.exe / http / js / functions.js next >
Text File  |  2010-01-30  |  38KB  |  1,079 lines

  1. /*****************************************************************************
  2.  * functions.js: VLC media player web interface
  3.  *****************************************************************************
  4.  * Copyright (C) 2005-2006 the VideoLAN team
  5.  * $Id$
  6.  *
  7.  * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /**********************************************************************
  25.  * Global variables
  26.  *********************************************************************/
  27.  
  28. var old_time = 0;
  29. var pl_cur_id;
  30. var albumart_id = -1;
  31.  
  32. /**********************************************************************
  33.  * Slider functions
  34.  *********************************************************************/
  35.  
  36. var slider_mouse_down = 0;
  37. var slider_dx = 0;
  38.  
  39. /* findPosX() from http://www.quirksmode.rg/js/indpos.html */
  40. function findPosX(obj)
  41. {
  42.     var curleft = 0;
  43.     if (obj.offsetParent)
  44.     {
  45.         while (obj.offsetParent)
  46.         {
  47.             curleft += obj.offsetLeft
  48.             obj = obj.offsetParent;
  49.         }
  50.     }
  51.     else if (obj.x)
  52.         curleft += obj.x;
  53.     return curleft;
  54. }
  55.  
  56. function slider_seek( e, bar )
  57. {
  58.     seek(Math.floor(( e.clientX + document.body.scrollLeft - findPosX( bar )) / 4)+"%25");
  59. }
  60. function slider_down( e, point )
  61. {
  62.     slider_mouse_down = 1;
  63.     slider_dx = e.clientX - findPosX( point );
  64. }
  65. function slider_up( e, bar )
  66. {
  67.     slider_mouse_down = 0;
  68.     /* slider_seek( e, bar ); */
  69. }
  70. function slider_move( e, bar )
  71. {
  72.     if( slider_mouse_down == 1 )
  73.     {
  74.         var slider_position  = Math.floor( e.clientX - slider_dx + document.body.scrollLeft - findPosX( bar ));
  75.         document.getElementById( 'main_slider_point' ).style.left = slider_position+"px";
  76.         slider_seek( e, bar );
  77.     }
  78. }
  79.  
  80. /**********************************************************************
  81.  * Misc utils
  82.  *********************************************************************/
  83.  
  84. /* XMLHttpRequest wrapper */
  85. function loadXMLDoc( url, callback )
  86. {
  87.   // branch for native XMLHttpRequest object
  88.   if ( window.XMLHttpRequest )
  89.   {
  90.     req = new XMLHttpRequest();
  91.     req.onreadystatechange = callback;
  92.     req.open( "GET", url, true );
  93.     req.send( null );
  94.   // branch for IE/Windows ActiveX version
  95.   }
  96.   else if ( window.ActiveXObject )
  97.   {
  98.     req = new ActiveXObject( "Microsoft.XMLHTTP" );
  99.     if ( req )
  100.     {
  101.       req.onreadystatechange = callback;
  102.       req.open( "GET", url, true );
  103.       req.send();
  104.     }
  105.   }
  106. }
  107.  
  108. /* fomat time in second as hh:mm:ss */
  109. function format_time( s )
  110. {
  111.     var hours = Math.floor(s/3600);
  112.     var minutes = Math.floor((s/60)%60);
  113.     var seconds = Math.floor(s%60);
  114.     if( hours < 10 ) hours = "0"+hours;
  115.     if( minutes < 10 ) minutes = "0"+minutes;
  116.     if( seconds < 10 ) seconds = "0"+seconds;
  117.     return hours+":"+minutes+":"+seconds;
  118. }
  119.  
  120. /* delete all a tag's children and add a text child node */
  121. function set_text( id, val )
  122. {
  123.     var elt = document.getElementById( id );
  124.     while( elt.hasChildNodes() )
  125.         elt.removeChild( elt.firstChild );
  126.     elt.appendChild( document.createTextNode( val ) );
  127. }
  128.  
  129. /* set item's 'element' attribute to value */
  130. function set_css( item, element, value )
  131. {
  132.     for( var j = 0; j < document.styleSheets.length; j++ )
  133.     {
  134.         var cssRules = document.styleSheets[j].cssRules;
  135.         if( !cssRules ) cssRules = document.styleSheets[j].rules;
  136.         for( var i = 0; i < cssRules.length; i++)
  137.         {
  138.             if( cssRules[i].selectorText == item )
  139.             {
  140.                 if( cssRules[i].style.setProperty )
  141.                     cssRules[i].style.setProperty( element, value, null );
  142.                 else
  143.                     cssRules[i].style.setAttribute( toCamelCase( element ), value );
  144.                 return;
  145.             }
  146.         }
  147.     }
  148. }
  149.  
  150. /* get item's 'element' attribute */
  151. function get_css( item, element )
  152. {
  153.     for( var j = 0; j < document.styleSheets.length; j++ )
  154.     {
  155.         var cssRules = document.styleSheets[j].cssRules;
  156.         if( !cssRules ) cssRules = document.styleSheets[j].rules;
  157.         for( var i = 0; i < cssRules.length; i++)
  158.         {
  159.             if( cssRules[i].selectorText == item )
  160.             {
  161.                 if( cssRules[i].style.getPropertyValue )
  162.                     return cssRules[i].style.getPropertyValue( element );
  163.                 else
  164.                     return cssRules[i].style.getAttribute( toCamelCase( element ) );
  165.             }
  166.         }
  167.     }
  168. }
  169.  
  170. function toggle_show( id )
  171. {
  172.     var element = document.getElementById( id );
  173.     if( element.style.display == 'block' || element.style.display == '' )
  174.     {
  175.         element.style.display = 'none';
  176.     }
  177.     else
  178.     {
  179.         element.style.display = 'block';
  180.     }
  181. }
  182. function toggle_show_node( id )
  183. {
  184.     var element = document.getElementById( 'pl_'+id );
  185.     var img = document.getElementById( 'pl_img_'+id );
  186.     if( element.style.display == 'block' || element.style.display == '' )
  187.     {
  188.         element.style.display = 'none';
  189.         img.setAttribute( 'src', 'images/plus.png' );
  190.         img.setAttribute( 'alt', '[+]' );
  191.     }
  192.     else
  193.     {
  194.         element.style.display = 'block';
  195.         img.setAttribute( 'src', 'images/minus.png' );
  196.         img.setAttribute( 'alt', '[-]' );
  197.     }
  198. }
  199.  
  200. function show( id ){ document.getElementById( id ).style.display = 'block'; }
  201. function showinline( id ){ document.getElementById( id ).style.display = 'inline'; }
  202.  
  203. function hide( id ){ document.getElementById( id ).style.display = 'none'; }
  204.  
  205. function checked( id ){ return document.getElementById( id ).checked; }
  206.  
  207. function value( id ){ return document.getElementById( id ).value; }
  208.  
  209. function setclass( obj, value )
  210. {
  211.     obj.setAttribute( 'class', value ); /* Firefox */
  212.     obj.setAttribute( 'className', value ); /* IE */
  213. }
  214.  
  215. function radio_value( name )
  216. {
  217.     var radio = document.getElementsByName( name );
  218.     for( var i = 0; i < radio.length; i++ )
  219.     {
  220.         if( radio[i].checked )
  221.         {
  222.             return radio[i].value;
  223.         }
  224.     }
  225.     return "";
  226. }
  227.  
  228. function check_and_replace_int( id, val )
  229. {
  230.     var objRegExp = /^\d+$/;
  231.     if( value( id ) != ''
  232.         && ( !objRegExp.test( value( id ) )
  233.              || parseInt( value( id ) ) < 1 ) )
  234.         return document.getElementById( id ).value = val;
  235.     return document.getElementById( id ).value;
  236. }
  237.  
  238. function addslashes( str ){ return str.replace(/\'/g, '\\\''); }
  239. function escapebackslashes( str ){ return str.replace(/\\/g, '\\\\'); }
  240.  
  241. function toCamelCase( str )
  242. {
  243.     str = str.split( '-' );
  244.     var cml = str[0];
  245.     for( var i=1; i<str.length; i++)
  246.         cml += str[i].charAt(0).toUpperCase()+str[i].substring(1);
  247.     return cml;
  248. }
  249.  
  250. function disable( id ){ document.getElementById( id ).disabled = true; }
  251.  
  252. function enable( id ){ document.getElementById( id ).disabled = false; }
  253.  
  254. function button_over( element ){ element.style.border = "1px solid #000"; }
  255.  
  256. function button_out( element ){ element.style.border = "1px solid #fff"; }
  257. function button_out_menu( element ){ element.style.border = "1px solid transparent"; }
  258.  
  259. function show_menu( id ){ document.getElementById(id).style.display = 'block'; }
  260. function hide_menu( id ){ document.getElementById(id).style.display = 'none'; }
  261.  
  262. /* toggle show help under the buttons */
  263. function toggle_btn_text()
  264. {
  265.     if( get_css( '.btn_text', 'display' ) == 'none' )
  266.     {
  267.         set_css( '.btn_text', 'display', 'block' );
  268.     }
  269.     else
  270.     {
  271.         set_css( '.btn_text', 'display', 'none' );
  272.     }
  273. }
  274.  
  275. function clear_children( elt )
  276. {   
  277.     if( elt )
  278.         while( elt.hasChildNodes() )
  279.             elt.removeChild( elt.firstChild );
  280. }
  281.  
  282. /**********************************************************************
  283.  * Interface actions
  284.  *********************************************************************/
  285. /* input actions */
  286. function in_play()
  287. {
  288.     var input = value('input_mrl');
  289.     if( value('sout_mrl') != '' )
  290.         input += ' '+value('sout_mrl');
  291.     var url = 'requests/status.xml?command=in_play&input='+encodeURIComponent( addslashes(escapebackslashes(input)) );
  292.     loadXMLDoc( url, parse_status );
  293.     setTimeout( 'update_playlist()', 1000 );
  294. }
  295. function in_enqueue()
  296. {
  297.     var input = value('input_mrl');
  298.     if( value('sout_mrl') != '' )
  299.         input += ' '+value('sout_mrl');
  300.     var url = 'requests/status.xml?command=in_enqueue&input='+encodeURIComponent( addslashes(escapebackslashes(input)) );
  301.     loadXMLDoc( url, parse_status );
  302.     setTimeout( 'update_playlist()', 1000 );
  303. }
  304.  
  305. /* playlist actions */
  306. function pl_play( id )
  307. {
  308.     loadXMLDoc( 'requests/status.xml?command=pl_play&id='+id, parse_status );
  309.     pl_cur_id = id;
  310.     setTimeout( 'update_playlist()', 1000 );
  311. }
  312. function pl_pause()
  313. {
  314.     loadXMLDoc( 'requests/status.xml?command=pl_pause&id='+pl_cur_id, parse_status );
  315. }
  316. function pl_stop()
  317. {
  318.     loadXMLDoc( 'requests/status.xml?command=pl_stop', parse_status );
  319.     setTimeout( 'update_playlist()', 1000 );
  320. }
  321. function pl_next()
  322. {
  323.     loadXMLDoc( 'requests/status.xml?command=pl_next', parse_status );
  324.     setTimeout( 'update_playlist()', 1000 );
  325. }
  326. function pl_previous()
  327. {
  328.     loadXMLDoc( 'requests/status.xml?command=pl_previous', parse_status );
  329.     setTimeout( 'update_playlist()', 1000 );
  330. }
  331. function pl_delete( id )
  332. {
  333.     loadXMLDoc( 'requests/status.xml?command=pl_delete&id='+id, parse_status );
  334.     setTimeout( 'update_playlist()', 1000 );
  335. }
  336. function pl_empty()
  337. {
  338.     loadXMLDoc( 'requests/status.xml?command=pl_empty', parse_status );
  339.     setTimeout( 'update_playlist()', 1000 );
  340. }
  341. function pl_sort( sort, order )
  342. {
  343.     loadXMLDoc( 'requests/status.xml?command=pl_sort&id='+order+'&val='+sort, parse_status );
  344.     setTimeout( 'update_playlist()', 1000 );
  345. }
  346. function pl_shuffle()
  347. {
  348.     loadXMLDoc( 'requests/status.xml?command=pl_random', parse_status );
  349.     setTimeout( 'update_playlist()', 1000 );
  350. }
  351. function pl_loop()
  352. {
  353.     loadXMLDoc( 'requests/status.xml?command=pl_loop', parse_status );
  354. }
  355. function pl_repeat()
  356. {
  357.     loadXMLDoc( 'requests/status.xml?command=pl_repeat', parse_status );
  358. }
  359. function pl_sd( value )
  360. {
  361.     loadXMLDoc( 'requests/status.xml?command=pl_sd&val='+value, parse_status );
  362. }
  363.  
  364. /* misc actions */
  365. function volume_down()
  366. {
  367.     loadXMLDoc( 'requests/status.xml?command=volume&val=-20', parse_status );
  368. }
  369. function volume_up()
  370. {
  371.     loadXMLDoc( 'requests/status.xml?command=volume&val=%2B20', parse_status );
  372. }
  373. function seek( pos )
  374. {
  375.     loadXMLDoc( 'requests/status.xml?command=seek&val='+pos, parse_status );
  376. }
  377. function fullscreen()
  378. {
  379.     loadXMLDoc( 'requests/status.xml?command=fullscreen', parse_status );
  380. }
  381. function snapshot()
  382. {
  383.     loadXMLDoc( 'requests/status.xml?command=snapshot', parse_status );
  384. }
  385. function hotkey( str )
  386. {
  387.     /* Use hotkey name (without the "key-" part) as the argument to simulate a hotkey press */
  388.     loadXMLDoc( 'requests/status.xml?command=key&val='+str, parse_status );
  389. }
  390. function update_status()
  391. {
  392.     loadXMLDoc( 'requests/status.xml', parse_status );
  393. }
  394. function update_playlist()
  395. {
  396.     loadXMLDoc( 'requests/playlist.xml', parse_playlist );
  397. }
  398.  
  399. /**********************************************************************
  400.  * Parse xml replies to XMLHttpRequests
  401.  *********************************************************************/
  402. /* parse request/status.xml */
  403. function parse_status()
  404. {
  405.     if( req.readyState == 4 )
  406.     {
  407.         if( req.status == 200 )
  408.         {
  409.             var status = req.responseXML.documentElement;
  410.             var timetag = status.getElementsByTagName( 'time' );
  411.             if( timetag.length > 0 )
  412.             {
  413.                 var new_time = timetag[0].firstChild.data;
  414.             }
  415.             else
  416.             {
  417.                 new_time = old_time;
  418.             }
  419.             var lengthtag = status.getElementsByTagName( 'length' );
  420.             var length;
  421.             if( lengthtag.length > 0 )
  422.             {
  423.                 length = lengthtag[0].firstChild.data;
  424.             }
  425.             else
  426.             {
  427.                 length = 0;
  428.             }
  429.             var slider_position;
  430.             positiontag = status.getElementsByTagName( 'position' );
  431.             if( length < 100 && positiontag.length > 0 )
  432.             {
  433.                 slider_position = ( positiontag[0].firstChild.data * 4 ) + "px";
  434.             }
  435.             else if( length > 0 )
  436.             {
  437.                 /* this is more precise if length > 100 */
  438.                 slider_position = Math.floor( ( new_time * 400 ) / length ) + "px";
  439.             }
  440.             else
  441.             {
  442.                 slider_position = 0;
  443.             }
  444.             if( old_time > new_time )
  445.                 setTimeout('update_playlist()',50);
  446.             old_time = new_time;
  447.             set_text( 'time', format_time( new_time ) );
  448.             set_text( 'length', format_time( length ) );
  449.             if( status.getElementsByTagName( 'volume' ).length != 0 )
  450.                 set_text( 'volume', Math.floor(status.getElementsByTagName( 'volume' )[0].firstChild.data/5.12)+'%' );
  451.             var statetag = status.getElementsByTagName( 'state' );
  452.             if( statetag.length > 0 )
  453.             {
  454.                 set_text( 'state', statetag[0].firstChild.data );
  455.             }
  456.             else
  457.             {
  458.                 set_text( 'state', '(?)' );
  459.             }
  460.             if( slider_mouse_down == 0 )
  461.             {
  462.                 document.getElementById( 'main_slider_point' ).style.left = slider_position;
  463.             }
  464.             var statustag = status.getElementsByTagName( 'state' );
  465.             if( statustag.length > 0 ? statustag[0].firstChild.data == "playing" : 0 )
  466.             {
  467.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/pause.png' );
  468.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'alt', 'Pause' );
  469.                 document.getElementById( 'btn_pause' ).setAttribute( 'title', 'Pause' );
  470.             }
  471.             else
  472.             {
  473.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/play.png' );
  474.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'alt', 'Play' );
  475.                 document.getElementById( 'btn_pause' ).setAttribute( 'title', 'Play' );
  476.             }
  477.  
  478.             var randomtag = status.getElementsByTagName( 'random' );
  479.             if( randomtag.length > 0 ? randomtag[0].firstChild.data == "1" : 0)
  480.                 setclass( document.getElementById( 'btn_shuffle'), 'on' );
  481.             else
  482.                 setclass( document.getElementById( 'btn_shuffle'), 'off' );
  483.                
  484.             var looptag = status.getElementsByTagName( 'loop' );
  485.             if( looptag.length > 0 ? looptag[0].firstChild.data == "1" : 0)
  486.                 setclass( document.getElementById( 'btn_loop'), 'on' );
  487.             else
  488.                 setclass( document.getElementById( 'btn_loop'), 'off' );
  489.  
  490.             var repeattag = status.getElementsByTagName( 'repeat' );
  491.             if( repeattag.length > 0 ? repeattag[0].firstChild.data == "1" : 0 )
  492.                 setclass( document.getElementById( 'btn_repeat'), 'on' );
  493.             else
  494.                 setclass( document.getElementById( 'btn_repeat'), 'off' );
  495.  
  496.             var tree = document.createElement( "ul" );
  497.             var categories = status.getElementsByTagName( 'category' );
  498.             var i;
  499.             for( i = 0; i < categories.length; i++ )
  500.             {
  501.                 var item = document.createElement( "li" );
  502.                 item.appendChild( document.createTextNode( categories[i].getAttribute( 'name' ) ) );
  503.                 var subtree = document.createElement( "dl" );
  504.                 var infos = categories[i].getElementsByTagName( 'info' );
  505.                 var j;
  506.                 for( j = 0; j < infos.length; j++ )
  507.                 {
  508.                     var subitem = document.createElement( "dt" );
  509.                     subitem.appendChild( document.createTextNode( infos[j].getAttribute( 'name' ) ) );
  510.                     subtree.appendChild( subitem );
  511.                     if( infos[j].hasChildNodes() )
  512.                     {
  513.                         var subitem = document.createElement( "dd" );
  514.                         subitem.appendChild( document.createTextNode( infos[j].firstChild.data ) );
  515.                         subtree.appendChild( subitem );
  516.                     }
  517.                 }
  518.                 item.appendChild( subtree );
  519.                 tree.appendChild( item );
  520.             }
  521.             var infotree = document.getElementById('infotree' );
  522.             clear_children( infotree );
  523.             infotree.appendChild( tree );
  524.             
  525.         }
  526.         else
  527.         {
  528.             /*alert( 'Error! HTTP server replied: ' + req.status );*/
  529.         }
  530.     }
  531. }
  532.  
  533. /* parse playlist.xml */
  534. function parse_playlist()
  535. {
  536.     if( req.readyState == 4 )
  537.     {
  538.         if( req.status == 200 )
  539.         {
  540.             var answer = req.responseXML.documentElement;
  541.             var playtree = document.getElementById( 'playtree' );
  542.             var pos = document.createElement( "div" );
  543.             var pos_top = pos;
  544.             var elt = answer.firstChild;
  545.             
  546.             pl_cur_id = 0;  /* changed to the current id is there actually
  547.                              * is a current id */
  548.             while( elt )
  549.             {
  550.                 if( elt.nodeName == "node" )
  551.                 {
  552.                     if( pos.hasChildNodes() )
  553.                         pos.appendChild( document.createElement( "br" ) );
  554.                     var nda = document.createElement( 'a' );
  555.                     nda.setAttribute( 'href', 'javascript:toggle_show_node(\''+elt.getAttribute( 'id' )+'\');' );
  556.                     var ndai = document.createElement( 'img' );
  557.                     ndai.setAttribute( 'src', 'images/minus.png' );
  558.                     ndai.setAttribute( 'alt', '[-]' );
  559.                     ndai.setAttribute( 'id', 'pl_img_'+elt.getAttribute( 'id' ) );
  560.                     nda.appendChild( ndai );
  561.                     pos.appendChild( nda );
  562.                     pos.appendChild( document.createTextNode( ' ' + elt.getAttribute( 'name' ) ) );
  563.  
  564.                     if( elt.getAttribute( 'ro' ) == 'rw' )
  565.                     {
  566.                         pos.appendChild( document.createTextNode( ' ' ) );
  567.                         var del = document.createElement( "a" );
  568.                         del.setAttribute( 'href', 'javascript:pl_delete('+elt.getAttribute( 'id' )+')' );
  569.                             var delimg = document.createElement( "img" );
  570.                             delimg.setAttribute( 'src', 'images/delete_small.png' );
  571.                             delimg.setAttribute( 'alt', '(delete)' );
  572.                         del.appendChild( delimg );
  573.                         pos.appendChild( del );
  574.                     }
  575.  
  576.                     var nd = document.createElement( "div" );
  577.                     setclass( nd, 'pl_node' );
  578.                     nd.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
  579.                     pos.appendChild( nd );
  580.                 }
  581.                 else if( elt.nodeName == "leaf" )
  582.                 {
  583.                     if( pos.hasChildNodes() )
  584.                     pos.appendChild( document.createElement( "br" ) );
  585.                     var pl = document.createElement( "a" );
  586.                     setclass( pl, 'pl_leaf' );
  587.                     pl.setAttribute( 'href', 'javascript:pl_play('+elt.getAttribute( 'id' )+');' );
  588.                     pl.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
  589.                     if( elt.getAttribute( 'current' ) == 'current' )
  590.                     {
  591.                         pl.style.fontWeight = 'bold';
  592.                         var nowplaying = document.getElementById( 'nowplaying' );
  593.                         clear_children( nowplaying );
  594.                         nowplaying.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
  595.                         pl.appendChild( document.createTextNode( '* '));
  596.                         pl_cur_id = elt.getAttribute( 'id' );
  597.                     }
  598.                     pl.setAttribute( 'title', elt.getAttribute( 'uri' ));
  599.                     pl.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
  600.                     var duration = elt.getAttribute( 'duration' );
  601.                     if( duration > 0 )
  602.                         pl.appendChild( document.createTextNode( " (" + format_time( elt.getAttribute( 'duration' ) / 1000000 ) + ")" ) );
  603.                     pos.appendChild( pl );
  604.  
  605.                     if( elt.getAttribute( 'ro' ) == 'rw' )
  606.                     {
  607.                         pos.appendChild( document.createTextNode( ' ' ) );
  608.                         var del = document.createElement( "a" );
  609.                         del.setAttribute( 'href', 'javascript:pl_delete('+elt.getAttribute( 'id' )+')' );
  610.                             var delimg = document.createElement( "img" );
  611.                             delimg.setAttribute( 'src', 'images/delete_small.png' );
  612.                             delimg.setAttribute( 'alt', '(delete)' );
  613.                         del.appendChild( delimg );
  614.                         pos.appendChild( del );
  615.                     }
  616.                 }
  617.                 if( elt.firstChild )
  618.                 {
  619.                     elt = elt.firstChild;
  620.                     pos = pos.lastChild;
  621.                 }
  622.                 else if( elt.nextSibling )
  623.                 {
  624.                     elt = elt.nextSibling;
  625.                     pos = pos;
  626.                 }
  627.                 else
  628.                 {
  629.                     while( ! elt.parentNode.nextSibling )
  630.                     {
  631.                         elt = elt.parentNode;
  632.                         if( ! elt.parentNode ) break;
  633.                         pos = pos.parentNode;
  634.                     }
  635.                     if( ! elt.parentNode ) break;
  636.                     elt = elt.parentNode.nextSibling;
  637.                     pos = pos.parentNode;
  638.                 }
  639.             }
  640.             clear_children( playtree );
  641.             playtree.appendChild( pos_top );
  642.         }
  643.         else
  644.         {
  645.             /*alert( 'Error! HTTP server replied: ' + req.status );*/
  646.         }
  647.     }
  648. }
  649.  
  650. /* parse browse.xml */
  651. function parse_browse_dir( )
  652. {
  653.     if( req.readyState == 4 )
  654.     {
  655.         if( req.status == 200 )
  656.         {
  657.             var answer = req.responseXML.documentElement;
  658.             if( !answer ) return;
  659.             var browser = document.getElementById( 'browser' );
  660.             var pos = document.createElement( "div" );
  661.             var elt = answer.firstChild;
  662.             while( elt )
  663.             {
  664.                 if( elt.nodeName == "element" )
  665.                 {
  666.                     var item = document.createElement( "a" );
  667.                     setclass( item, 'browser' );
  668.                     if( elt.getAttribute( 'type' ) == 'directory' )
  669.                     {
  670.                         item.setAttribute( 'href', 'javascript:browse_dir(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');');
  671.                     }
  672.                     else
  673.                     {
  674.                         item.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');' );
  675.                     }
  676.                     item.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
  677.                     pos.appendChild( item );
  678.                     if( elt.getAttribute( 'type' ) == 'directory' )
  679.                     {
  680.                         pos.appendChild( document.createTextNode( ' ' ) );
  681.                         var item = document.createElement( "a" );
  682.                         setclass( item, 'browser' );
  683.                         item.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');');
  684.                         item.appendChild( document.createTextNode( '(select)' ) );
  685.                         pos.appendChild( item );
  686.                     }
  687.                     pos.appendChild( document.createElement( "br" ) );
  688.                 }
  689.                 elt = elt.nextSibling;
  690.             }
  691.             clear_children( browser );
  692.             browser.appendChild( pos );
  693.         }
  694.         else
  695.         {
  696.             /*alert( 'Error! HTTP server replied: ' + req.status );*/
  697.         }
  698.     }
  699. }
  700.  
  701. /**********************************************************************
  702.  * Input dialog functions
  703.  *********************************************************************/
  704. function hide_input( )
  705. {
  706.     document.getElementById( 'input_file' ).style.display = 'none';
  707.     document.getElementById( 'input_disc' ).style.display = 'none';
  708.     document.getElementById( 'input_network' ).style.display = 'none';
  709.     document.getElementById( 'input_fake' ).style.display = 'none';
  710. }
  711.  
  712. /* update the input MRL using data from the input file helper */
  713. /* FIXME ... subs support */
  714. function update_input_file()
  715. {
  716.     var mrl = document.getElementById( 'input_mrl' );
  717.  
  718.     mrl.value = value( 'input_file_filename' );
  719. }
  720.  
  721. /* update the input MRL using data from the input disc helper */
  722. function update_input_disc()
  723. {
  724.     var mrl     = document.getElementById( 'input_mrl' );
  725.     var type    = radio_value( "input_disc_type" );
  726.     var device  = value( "input_disc_dev" );
  727.  
  728.     var title   = check_and_replace_int( 'input_disc_title', 0 );
  729.     var chapter = check_and_replace_int( 'input_disc_chapter', 0 );
  730.     var subs    = check_and_replace_int( 'input_disc_subtrack', '' );
  731.     var audio   = check_and_replace_int( 'input_disc_audiotrack', 0 );
  732.  
  733.     mrl.value = "";
  734.  
  735.     if( type == "dvd" )
  736.     {
  737.         mrl.value += "dvd://";
  738.     }
  739.     else if( type == "dvdsimple" )
  740.     {
  741.         mrl.value += "dvdsimple://";
  742.     }
  743.     else if( type == "vcd" )
  744.     {
  745.         mrl.value += "vcd://";
  746.     }
  747.     else if( type == "cdda" )
  748.     {
  749.         mrl.value += "cdda://";
  750.     }
  751.  
  752.     mrl.value += device;
  753.  
  754.     if( title )
  755.     {
  756.         mrl.value += "@"+title;
  757.         if( chapter && type != "cdda" )
  758.             mrl.value += ":"+chapter;
  759.     }
  760.  
  761.     if( type != "cdda" )
  762.     {
  763.         if( subs != '' )
  764.             mrl.value += " :sub-track="+subs;
  765.         if( audio != '' )
  766.             mrl.value += " :audio-track="+audio;
  767.     }
  768.  
  769. }
  770.  
  771. /* update the input MRL using data from the input network helper */
  772. function update_input_net()
  773. {
  774.     var mrl = document.getElementById( 'input_mrl' );
  775.     var type = radio_value( "input_net_type" );
  776.     
  777.     check_and_replace_int( 'input_net_udp_port', 1234 );
  778.     check_and_replace_int( 'input_net_udpmcast_port', 1234 );
  779.  
  780.     mrl.value = "";
  781.  
  782.     if( type == "udp" )
  783.     {
  784.         mrl.value += "udp://";
  785.         if( checked( 'input_net_udp_forceipv6' ) )
  786.             mrl.value += "[::]";
  787.         if( value( 'input_net_udp_port' ) )
  788.             mrl.value += ":"+value( 'input_net_udp_port' );
  789.     }
  790.     else if( type == "udpmcast" )
  791.     {
  792.         mrl.value += "udp://@"+value( 'input_net_udpmcast_address');
  793.         if( value( 'input_net_udpmcast_port' ) )
  794.             mrl.value += ":"+value( 'input_net_udpmcast_port' );
  795.     }
  796.     else if( type == "http" )
  797.     {
  798.         var url = value( 'input_net_http_url' );
  799.         if( url.substring(0,7) != "http://"
  800.             && url.substring(0,8) != "https://"
  801.             && url.substring(0,6) != "ftp://"
  802.             && url.substring(0,6) != "mms://"
  803.             && url.substring(0,7) != "mmsh://" )
  804.             mrl.value += "http://";
  805.         mrl.value += url;
  806.     }
  807.     else if( type == "rtsp" )
  808.     {
  809.         var url = value( 'input_net_rtsp_url' );
  810.         if( url.substring(0,7) != "rtsp://" )
  811.             mrl.value += "rtsp://";
  812.         mrl.value += url;
  813.     }
  814.  
  815.     if( checked( "input_net_timeshift" ) )
  816.         mrl.value += " :access-filter=timeshift";
  817. }
  818.  
  819. /* update the input MRL using data from the input fake helper */
  820. function update_input_fake()
  821. {
  822.     var mrl = document.getElementById( 'input_mrl' );
  823.  
  824.     mrl.value = "fake://";
  825.     mrl.value += " :fake-file=" + value( "input_fake_filename" );
  826.  
  827.     if( value( "input_fake_width" ) )
  828.         mrl.value += " :fake-width=" + value( "input_fake_width" );
  829.     if( value( "input_fake_height" ) )
  830.         mrl.value += " :fake-height=" + value( "input_fake_height" );
  831.     if( value( "input_fake_ar" ) )
  832.         mrl.value += " :fake-ar=" + value( "input_fake_ar" );
  833. }
  834.  
  835. /**********************************************************************
  836.  * Sout dialog functions
  837.  *********************************************************************/
  838. /* toggle show the full sout interface */
  839. function toggle_show_sout_helper()
  840. {
  841.     var element = document.getElementById( "sout_helper" );
  842.     if( element.style.display == 'block' )
  843.     {
  844.         element.style.display = 'none';
  845.         document.getElementById( "sout_helper_toggle" ).value = 'Full sout interface';
  846.     }
  847.     else
  848.     {
  849.         element.style.display = 'block';
  850.         document.getElementById( "sout_helper_toggle" ).value = 'Hide sout interface';
  851.     }
  852. }
  853.  
  854. /* update the sout MRL using data from the sout_helper */
  855. function update_sout()
  856. {
  857.     var mrl = document.getElementById( 'sout_mrl' );
  858.     mrl.value = "";
  859.  
  860.     check_and_replace_int( 'sout_http_port', 8080 );
  861.     check_and_replace_int( 'sout_mmsh_port', 8080 );
  862.     check_and_replace_int( 'sout_rtp_port', 1234 );
  863.     check_and_replace_int( 'sout_udp_port', 1234 );
  864.     check_and_replace_int( 'sout_ttl', 1 );
  865.  
  866.     if( checked( 'sout_soverlay' ) )
  867.     {
  868.         disable( 'sout_scodec' );
  869.         disable( 'sout_sub' );
  870.     }
  871.     else
  872.     {
  873.         enable( 'sout_scodec' );
  874.         enable( 'sout_sub' );
  875.     }
  876.  
  877.     var transcode =  checked( 'sout_vcodec_s' ) || checked( 'sout_acodec_s' )
  878.                   || checked( 'sout_sub' )      || checked( 'sout_soverlay' );
  879.  
  880.     if( transcode )
  881.     {
  882.         mrl.value += ":sout=#transcode{";
  883.         var alot = false; /* alot == at least one transcode */
  884.         if( checked( 'sout_vcodec_s' ) )
  885.         {
  886.             mrl.value += "vcodec="+value( 'sout_vcodec' )+",vb="+value( 'sout_vb' )+",scale="+value( 'sout_scale' );
  887.             alot = true;
  888.         }
  889.         if( checked( 'sout_acodec_s' ) )
  890.         {
  891.             if( alot ) mrl.value += ",";
  892.             mrl.value += "acodec="+value( 'sout_acodec' )+",ab="+value( 'sout_ab' );
  893.             if( value( 'sout_channels' ) )
  894.                 mrl.value += ",channels="+value( 'sout_channels' );
  895.             alot = true;
  896.         }
  897.         if( checked( 'sout_soverlay' ) )
  898.         {
  899.             if( alot ) mrl.value += ",";
  900.             mrl.value += "soverlay";
  901.             alot = true;
  902.         }
  903.         else if( checked( 'sout_sub' ) )
  904.         {
  905.             if( alot ) mrl.value += ",";
  906.             mrl.value += "scodec="+value( 'sout_scodec' );
  907.             alot = true;
  908.         }
  909.         mrl.value += value( 'sout_transcode_extra' );
  910.             
  911.         mrl.value += "}";
  912.     }
  913.  
  914.     var output = checked( 'sout_display' ) + checked( 'sout_file' )
  915.                + checked( 'sout_http' )    + checked( 'sout_mmsh' )
  916.                + checked( 'sout_rtp' )     + checked( 'sout_udp' );
  917.  
  918.     if( output )
  919.     {
  920.         if( transcode )
  921.             mrl.value += ":";
  922.         else
  923.             mrl.value += ":sout=#";
  924.         var aloo = false; /* aloo == at least one output */
  925.         var mux = radio_value( 'sout_mux' );
  926.         var ttl = parseInt( value( 'sout_ttl' ) );
  927.         if( output > 1 ) mrl.value += "duplicate{";
  928.         if( checked( 'sout_display' ) )
  929.         {
  930.             if( output > 1 ) mrl.value += "dst="
  931.             mrl.value += "display";
  932.             aloo = true;
  933.         }
  934.         if( checked( 'sout_file' ) )
  935.         {
  936.             if( aloo ) mrl.value += ",";
  937.             if( output > 1 ) mrl.value += "dst="
  938.             mrl.value += "std{access=file,mux="+mux+",dst="+value( 'sout_file_filename' )+"}";
  939.             aloo = true;
  940.         }
  941.         if( checked( 'sout_http' ) )
  942.         {
  943.             if( aloo ) mrl.value += ",";
  944.             if( output > 1 ) mrl.value += "dst="
  945.             mrl.value += "std{access=http,mux="+mux+",dst="+value( 'sout_http_addr' );
  946.             if( value( 'sout_http_port' ) )
  947.                 mrl.value += ":"+value( 'sout_http_port' );
  948.             mrl.value += "}";
  949.             aloo = true;
  950.         }
  951.         if( checked( 'sout_mmsh' ) )
  952.         {
  953.             if( aloo ) mrl.value += ",";
  954.             if( output > 1 ) mrl.value += "dst="
  955.             mrl.value += "std{access=mmsh,mux="+mux+",dst="+value( 'sout_mmsh_addr' );
  956.             if( value( 'sout_mmsh_port' ) )
  957.                 mrl.value += ":"+value( 'sout_mmsh_port' );
  958.             mrl.value += "}";
  959.             aloo = true;
  960.         }
  961.         if( checked( 'sout_rtp' ) )
  962.         {
  963.             if( aloo ) mrl.value += ",";
  964.             if( output > 1 ) mrl.value += "dst="
  965.             mrl.value += "std{access=rtp";
  966.             if( ttl ) mrl.value += "{ttl="+ttl+"}";
  967.             mrl.value += ",mux="+mux+",dst="+value( 'sout_rtp_addr' );
  968.             if( value( 'sout_rtp_port' ) )
  969.                 mrl.value += ":"+value( 'sout_rtp_port' );
  970.             if( checked( 'sout_sap' ) )
  971.             {
  972.                 mrl.value += ",sap";
  973.                 if( value( 'sout_sap_group' ) != '' )
  974.                 {
  975.                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
  976.                 }
  977.                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
  978.             }
  979.             mrl.value += "}";
  980.             aloo = true;
  981.         }
  982.         if( checked( 'sout_udp' ) )
  983.         {
  984.             if( aloo ) mrl.value += ",";
  985.             if( output > 1 ) mrl.value += "dst="
  986.             mrl.value += "std{access=udp";
  987.             if( ttl ) mrl.value += "{ttl="+ttl+"}";
  988.             mrl.value += ",mux="+mux+",dst="+value( 'sout_udp_addr' );
  989.             if( value('sout_udp_port' ) )
  990.                 mrl.value += ":"+value( 'sout_udp_port' );
  991.             if( checked( 'sout_sap' ) )
  992.             {
  993.                 mrl.value += ",sap";
  994.                 if( value( 'sout_sap_group' ) != '' )
  995.                 {
  996.                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
  997.                 }
  998.                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
  999.             }
  1000.             mrl.value += "}";
  1001.             aloo = true;
  1002.         }
  1003.         if( output > 1 ) mrl.value += "}";
  1004.     }
  1005.  
  1006.     if( ( transcode || output ) && checked( 'sout_all' ) )
  1007.         mrl.value += " :sout-all";
  1008. }
  1009.  
  1010. /* reset sout mrl value */
  1011. function reset_sout()
  1012. {
  1013.     document.getElementById('sout_mrl').value = value('sout_old_mrl');
  1014. }
  1015.  
  1016. /* save sout mrl value */
  1017. function save_sout()
  1018. {
  1019.     document.getElementById('sout_old_mrl').value = value('sout_mrl');
  1020. }
  1021.  
  1022. /**********************************************************************
  1023.  * Browser dialog functions
  1024.  *********************************************************************/
  1025. /* only browse() should be called directly */
  1026. function browse( dest )
  1027. {
  1028.     document.getElementById( 'browse_dest' ).value = dest;
  1029.     document.getElementById( 'browse_lastdir' ).value;
  1030.     browse_dir( document.getElementById( 'browse_lastdir' ).value );
  1031.     show( 'browse' );
  1032. }
  1033. function browse_dir( dir )
  1034. {
  1035.     document.getElementById( 'browse_lastdir' ).value = dir;
  1036.     loadXMLDoc( 'requests/browse.xml?dir='+encodeURIComponent(dir), parse_browse_dir );
  1037. }
  1038. function browse_path( p )
  1039. {
  1040.     document.getElementById( value( 'browse_dest' ) ).value = p;
  1041.     hide( 'browse' );
  1042.     document.getElementById( value( 'browse_dest' ) ).focus();
  1043. }
  1044. function refresh_albumart( force )
  1045. {
  1046.     if( albumart_id != pl_cur_id || force )
  1047.     {
  1048.         var now = new Date();
  1049.         var albumart = document.getElementById( 'albumart' );
  1050.         albumart.src = '/art?timestamp=' + now.getTime();
  1051.         albumart_id = pl_cur_id;
  1052.     }
  1053. }
  1054. /**********************************************************************
  1055.  * Periodically update stuff in the interface
  1056.  *********************************************************************/
  1057. function loop_refresh_status()
  1058. {
  1059.     setTimeout( 'loop_refresh_status()', 1000 );
  1060.     update_status();
  1061. }
  1062. function loop_refresh_playlist()
  1063. {
  1064.     /* setTimeout( 'loop_refresh_playlist()', 10000 ); */
  1065.     update_playlist();
  1066. }
  1067. function loop_refresh_albumart()
  1068. {
  1069.     setTimeout( 'loop_refresh_albumart()', 1000 );
  1070.     refresh_albumart( false );
  1071. }
  1072. function loop_refresh()
  1073. {
  1074.     setTimeout( 'loop_refresh_status()', 1 );
  1075.     setTimeout( 'loop_refresh_playlist()', 1 );
  1076.     setTimeout( 'loop_refresh_albumart()', 1 );
  1077. }
  1078.  
  1079.